//
// Created by voyagerhui on 2022/3/18.
//
#include "solver.h"

/*-------------PolicySolver-------------*/
void PolicySolver::init(vector<vector<int>> qos1, map<string, vector<int>> demand1,
          map<string, int> site_bandwidth1, int qos_constraint1,
          vector<string> T_name1, vector<string> client_name1,
          vector<string> server_name1, map<string, int> client_name2idx1, map<string, int> server_name2idx1){
    qos = std::move(qos1);
    demand = std::move(demand1);
    site_bandwidth = std::move(site_bandwidth1);
    qos_constraint = qos_constraint1;
    T_name = std::move(T_name1);
    client_name = std::move(client_name1);
    server_name = std::move(server_name1);
    client_name2idx = std::move(client_name2idx1);
    server_name2idx = std::move(server_name2idx1);

    T = T_name.size();
    R = server_name.size();
    C = client_name.size();
    site_rest = {};
    ans = {};
    table = vector<vector<vector<int>>>(T, vector<vector<int>>(R, vector<int>(C, 0)));
}

void PolicySolver::greedy_policy() {
    for(int t=0; t<T; t++){
        site_rest = site_bandwidth;  // 每个时刻初始时剩余量
        // 遍历每个客户节点
        for(auto &cli_item:demand){
            string client_n = cli_item.first;
            int client_demand = cli_item.second[t];
            int client_idx = client_name2idx[client_n];

            string ans_row = client_n + ":";
            if(client_demand == 0){  // 需求为0的情况
                ans.push_back(ans_row);
                continue;
            }

            // 遍历每个边缘节点
            for(auto &ser_item:site_rest){
                string server_n = ser_item.first;
                int rest_flow = ser_item.second;
                if(rest_flow == 0) continue;
                int server_idx = server_name2idx[server_n];

                // 判断qos达标
                if(qos[server_idx][client_idx] >= qos_constraint) continue;

                // 边缘节点给客户节点提供服务
                if(rest_flow < client_demand){
                    client_demand -= rest_flow;
                    ser_item.second = 0;
                    table[t][server_idx][client_idx] = rest_flow;
                    ans_row += ("<" + server_n + "," + to_string(rest_flow) + ">,");
                }else{
                    ser_item.second -= client_demand;
                    table[t][server_idx][client_idx] = client_demand;
                    ans_row += ("<" + server_n + "," + to_string(client_demand) + ">");
                    break;
                }
            }
            ans.push_back(ans_row);
        }
    }
}

/*-------------PsoSolver-------------*/
void PsoSolver::init(vector<vector<int>> qos1, map<string, vector<int>> demand1,
                     map<string, int> site_bandwidth1, int qos_constraint1, vector<string> T_name1,
                     vector<string> client_name1, vector<string> server_name1,
                     vector<vector<vector<int>>> inital_table) {
    T = T_name1.size();
    R = server_name1.size();
    C = client_name1.size();
    idx_095 = ceil(T*0.95);

    qos = std::move(qos1);
    demand = std::move(demand1);
    site_bandwidth = std::move(site_bandwidth1);
    qos_constraint = qos_constraint1;
    T_name = T_name1;
    client_name = client_name1;
    server_name = server_name1;

    ban_cordinate = {};
    satisfied = vector<bool>(T);

    table = std::move(inital_table);
    table1d = vector<int>(T * R * C);
    col_sum = vector<vector<int>>(T, vector<int>(C, 0));
    row_sum = vector<vector<int>>(T, vector<int>(R, 0));

    table2table1d();
    for(int t=0; t<T; t++){
        cal_col_sum(t);
        cal_row_sum(t);
    }
    cal_ban_ordinate();
}

void PsoSolver::table2table1d(){
    int cnt = 0;
    for(int t=0; t<T; t++){
        for(int j=0; j < C; j++){
            for(int i=0; i < R; i++){
                table1d[cnt++] = table[t][i][j];
            }
        }
    }
}

void PsoSolver::table1d2table(){
    int cnt = 0;
    for(int t=0; t<T; t++) {
        for (int j = 0; j < C; j++) {
            for (int i = 0; i < R; i++) {
                table[t][i][j] = table1d[cnt++];
            }
        }
    }
    // qos不满足要求的位置置0
    for(auto &item:ban_cordinate){
        for(int t=0; t<T; t++){
            int i = item.first, j = item.second;
            table[t][i][j] = 0;
        }
    }

    // 更新行、列和
    for(int t=0; t<T; t++){
        cal_row_sum(t);
        cal_col_sum(t);
    }
}

void PsoSolver::cal_ban_ordinate(){
    for(int i=0; i < R; i++){
        for(int j=0; j < C; j++){
            if(qos[i][j] >= qos_constraint){
                ban_cordinate.emplace_back(i, j);  // 坐标(row, col)qos不达标
            }
        }
    }
}

void PsoSolver::cal_col_sum(int t) {
    for(int i=0; i < C; i++){
        int sum = 0;
        for(int j=0; j < R; j++){
            sum += table[t][j][i];
        }
        col_sum[t][i] = sum;
    }
}

void PsoSolver::cal_row_sum(int t) {
    for(int i=0; i < R; i++){
        int sum = 0;
        for(int j=0; j < C; j++){
            sum += table[t][i][j];
        }
        row_sum[t][i] = sum;
    }
}

void PsoSolver::adjust_table(int t) {
    ;
}

bool PsoSolver::is_time_t_satisfied(int t){
    for(auto& item:ban_cordinate){  // qos不满足
        int i = item.first, j = item.second;
        if(table[t][i][j] != 0){
            satisfied[t] = false;
            return false;
        }
    }
    for(int i=0; i < C; i++){
        if(col_sum[t][i] != demand[client_name[i]][t]){     // 客户需求不满足
            satisfied[t] = false;
            return false;
        }
    }
    for(int i=0; i < R; i++){
        if(row_sum[t][i] > site_bandwidth[server_name[i]]){         // 节点超出能提供的最大流量
            satisfied[t] = false;
            return false;
        }
    }
    satisfied[t] = true;
    return true;
}

bool PsoSolver::is_all_satisfied(){
    for (const auto item: satisfied)
        if (!item) {
            return false;
        }
    return true;
}

vector<int> PsoSolver::get_server_flow_seq(int idx){
    vector<int> row_i;
    for(int t=0; t<T; t++){
        row_i.push_back(row_sum[t][idx]);
    }
    sort(row_i.begin(), row_i.end());
    return row_i;
}

int PsoSolver::get_server_cost(int idx){
    vector<int> row_i;
    for(int t=0; t<T; t++){
        row_i.push_back(row_sum[t][idx]);
    }
    sort(row_i.begin(), row_i.end());
    return row_i[idx_095];  // 流量大小等于成本
}

void PsoSolver::check_constrains_break() {
    int row_dis = 0, col_dis = 0;
    for(int t=0; t<T; t++){
        for(int i=0; i<R; i++){
            if(row_sum[t][i] > site_bandwidth[server_name[i]]){
                row_dis ++;
                cout << "time " << t << " row " << i << " is over the ability" << endl;
            }
        }
        for(int i=0; i<C; i++){
            if(col_sum[t][i] < demand[client_name[i]][t]){
                col_dis ++;
                cout << "time " << t << " col " << i << " need more" << endl;
//                cout << "col_sum[t][i]=" << col_sum[t][i] << " demand[client_name[i]][t]=" << demand[client_name[i]][t] << endl;
            }
        }
    }
    cout << "rows break: " << row_dis << " cols break: " << col_dis << endl;
}


long long PsoSolver::get_cost(){
    // 等式约束不等式约束
    long long eq_cost = 0, iq_cost = 0, all_flow = 0;
    for(int t=0; t<T; t++){
        for(int i=0; i < C; i++){
            eq_cost += max(0, (demand[client_name[i]][t]-col_sum[t][i]));  // 等式约束
        }
        for(int i=0; i < R; i++){
            iq_cost += max(0, (row_sum[t][i] - site_bandwidth[server_name[i]]));  // 不等式约束
        }
    }

    // 边缘节点成本
    long long real_cost = 0;
    for(int i=0; i < R; i++){
        real_cost += get_server_cost(i);
    }
    static int cnt = 0;
    cnt ++;
    static int k1 = 1, k2 = 1, k3 = 100;
    if(cnt > 200){
//        cout << "changed" << endl;
//        k1 = min(100000, k1 + cnt);
//        k3 = max(0, k3 - cnt);
    }
    long long cost = k1*eq_cost+k2*iq_cost+k3*real_cost;  // 系数为正整数
    cout << eq_cost << " " << iq_cost << " " << real_cost << endl;
    return cost;
}

vector<string> PsoSolver::get_answer(){
    vector<string> ans;
    for(int t=0; t<T; t++){
        for(int i=0; i < C; i++){
            string client_ans = client_name[i]+":";
            for(int j=0; j < R; j++){
                if(table[t][j][i] > 0){
                    if(client_ans.back() == ':'){
                        client_ans += ("<"+server_name[j]+","+ to_string(table[t][j][i])+">");
                    }else{
                        client_ans += (",<"+server_name[j]+","+ to_string(table[t][j][i])+">");
                    }
                }
            }
            ans.push_back(client_ans);
        }
    }
    return ans;
}

void PsoSolver::pso_optimize() {
    srand((unsigned int)time(nullptr));

    // PSO 参数
    int x_dim = T * R * C;
    PSOPara psopara(x_dim);    // 变量维度——所有表的格子作为输入
    psopara.particle_num_ = 10;		// 粒子个数
    psopara.max_iter_num_ = 30;	// 最大迭代次数
    for(int i=0; i<x_dim; i++){
        psopara.dt_[i] = 1;			// 维度上的时间步长
        psopara.wstart_[i] = 0.8;   // 维度上的起始权重系数
        psopara.wend_[i] = 0.4;		// 维度上的终止权重系数
        psopara.C1_[i] = 250;         // 维度上的加速度因子
        psopara.C2_[i] = 250;	        // 维度上的加速度因子
        psopara.lower_bound_[i] = 0;        // 搜索下限
        psopara.upper_bound_[i] = 550000;	// 搜索上限
    }

    // PSO优化器
    PSOOptimizer psooptimizer(&psopara, FitnessFunction);
    long long *result = new long long[psooptimizer.max_iter_num_];
    // PSO优化
    psooptimizer.InitialAllParticles(table1d);  // 使用暴力解作为粒子的初始位置
    for (int i = 0; i < psooptimizer.max_iter_num_; i++) {
        psooptimizer.UpdateAllParticles();
        result[i] = psooptimizer.all_best_fitness_;
        cout << "Iteration No." << i << " fitness:" << result[i] << endl;
    }

    // 结果回写
    for(int i=0; i<x_dim; i++){
        table1d[i] = psooptimizer.all_best_position_[i];
    }
    table1d2table();
}

void PsoSolver::write_final_table() {
    FILE *fp;
    fp = fopen("./table.txt", "w+");
    for(int t=0; t<T; t++){
        fprintf(fp, "\nt=%d\n", t);
        for(int i=0; i<R; i++){
            for(int j=0; j<C; j++){
                fprintf(fp, "%d ", table[t][i][j]);
            }
            fprintf(fp, "\n");
        }
    }
}

vector<int> PsoSolver::matrix2vector(vector<vector<int>> a) {
    vector<int> a1d;
    for(int i=0; i<a.size(); i++){
        for(int j=0; j<a[0].size(); j++){
            a1d.push_back(a[i][j]);
        }
    }
    return a1d;
}

void PsoSolver::qp_optimize() {
    for(int t=0; t<T; t++){
        quadprogpp::Matrix<double> H, Aeq, A;
        quadprogpp::Vector<double> f, beq, b, x;

        int dim = R*C;
        x.resize(dim);

        // 目标函数
        H.resize(dim, dim);
        f.resize(dim);
        for(int i=0; i<dim; i++){
            for(int j=0; j<dim; j++){
                if(i == j) H[i][j] = 1;
                else H[i][j] = 0;
            }
        }
        for(int i=0; i<dim; i++) f[i] = 0;

        // 约束条件
        Aeq.resize(dim, C);  // Aeq.resize(C, dim);
        beq.resize(C);
        A.resize(dim, R);
        b.resize(R);
        // 对服务器提供量的不等式约束
        for(int i=0; i<R; i++){
            vector<vector<int>> a(R, vector<int>(C, 0));
            for(int j=0; j<C; j++){
                a[i][j] = -1;
            }
            vector<int> a1d = matrix2vector(a);
            for(int j=0; j<dim; j++){
                A[j][i] = a1d[j];  // 注意A[j][i] 顺序
            }
            b[i] = site_bandwidth[server_name[i]];
        }
        // 对客户需求量的等式约束
        for(int i=0; i<C; i++){
            vector<vector<int>> a(R, vector<int>(C, 0));
            for(int j=0; j<R; j++){
                if(qos[j][i] >= qos_constraint) a[j][i] = 0;  // qos 约束
                else a[j][i] = 1;
            }
            vector<int> a1d = matrix2vector(a);
            for(int j=0; j<dim; j++){
                Aeq[j][i] = a1d[j];
            }
            beq[i] = -demand[client_name[i]][t];
        }
        double Fitness = solve_quadprog(H, f, Aeq, beq, A, b, x);
//        cout << "t=" << t << " Fitness=" << Fitness << endl;
        // 写回t时刻结果
        int cnt = 0;
        for(int r=0; r<R; r++){
            for(int c=0; c<C; c++){
                table[t][r][c] = int(x[cnt])+1;
                cnt ++ ;
            }
        }
    }

    // 更新行、列和
    for(int t=0; t<T; t++){
        cal_row_sum(t);
        cal_col_sum(t);
    }
    // 检查有效性
    check_constrains_break();
    // 计算成本
    long long real_cost = 0;
    for(int i=0; i < R; i++){
        real_cost += get_server_cost(i);
    }
    cout << "cost = " << real_cost << endl;
}
